package top.meeting.room.module.book.services.impl;

import com.jfinal.kit.Kv;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.ehcache.CacheKit;
import com.xiaoleilu.hutool.date.DateUtil;
import net.dreamlu.event.EventKit;
import top.meeting.room.common.constant.ResultEnum;
import top.meeting.room.common.exceptions.HandlerException;
import top.meeting.room.common.kit.ListKit;
import top.meeting.room.module.book.event.ApproveEvent;
import top.meeting.room.module.book.event.BookMeetEvent;
import top.meeting.room.module.book.forms.ApproveForm;
import top.meeting.room.module.book.forms.BookForm;
import top.meeting.room.module.book.model.Book;
import top.meeting.room.module.book.query.BookQuery;
import top.meeting.room.module.book.services.IBookService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Lyt on 2017/9/11.
 */
public class BookService implements IBookService {

    public static final IBookService me = new BookService();

    private BookService() {
    }

    @Override
    public Page<Book> pageModel(BookQuery bookQuery) {
        Page<Book> retVal = null;
        if (bookQuery != null && bookQuery.getPage() != null && bookQuery.getSize() != null) {
            retVal = CacheKit.get(Book.book_pageModel, String.valueOf(bookQuery));
            final Kv set = Kv.by("params", bookQuery.getParams())
                    .set("firstDate", bookQuery.getFirstDate())
                    .set("lastDate", bookQuery.getLastDate());
            if (retVal == null) {
                SqlPara sqlPara = Book.dao.getSqlPara(Book.book_pageModel, set);
                sqlPara.setSql(sqlPara.getSql().replaceFirst(" AND ", " WHERE "));
                retVal = Book.dao.paginate(bookQuery.getPage(), bookQuery.getSize(), sqlPara);
                CacheKit.put(Book.book_pageModel, String.valueOf(bookQuery), retVal);
            }
        }
        return retVal;
    }

    @Override
    public Page<Record> pageRecord(BookQuery bookQuery) {
        Page<Record> retVal = CacheKit.get(Book.book_pageRecord, String.valueOf(bookQuery));
        if (retVal == null) {
            Page<Book> bookPage = pageModel(bookQuery);
            retVal = new Page<Record>(bookPage.getList().stream().map(book -> {
                return book.toDTO();
            }).collect(Collectors.toList()), bookPage.getPageNumber(), bookPage.getPageSize(), bookPage.getTotalPage(), bookPage.getTotalRow());
            CacheKit.put(Book.book_pageRecord, String.valueOf(bookQuery), retVal);
        }
        return retVal;
    }

    public Book getModel(Long id) {
        if (id == null)
            throw new HandlerException(ResultEnum.DATA_ERROR, "获取的个体ID不可以为空");
        Book retVal = CacheKit.get(Book.book_getModel, String.valueOf(id));
        if (retVal == null) {
            retVal = Book.dao.findById(id);
            CacheKit.put(Book.book_getModel, String.valueOf(id), retVal);
        }
        return retVal;
    }

    @Override
    public Record getRecord(Long id) {
        return null;
    }

    @Override
    public Book saveAsModel(BookForm bookForm) {
        return null;
    }

    @Override
    public Record saveAsRecord(BookForm bookForm) {
        return null;
    }

    public void deleteById(Long id) {
        deleteByIds(String.valueOf(id));
    }

    public void deleteByIds(String ids) {
        List<Long> idList = ListKit.ids2List(ids);
        SqlPara sqlPara = Db.getSqlPara(Book.book_deleteByIds, Kv.by("ids", idList));
        Db.update(sqlPara.getSql(), sqlPara.getPara());
        remove();
    }

    public List<Book> findBookList(BookQuery bookQuery) {
        List<Book> retVal = null;
        retVal = CacheKit.get(Book.book_modelList, String.valueOf(bookQuery));
        if (retVal == null) {
            Kv set = Kv.by("params", bookQuery.getParams())
                    .set("roomId", bookQuery.getRoomId())
                    .set("firstDate", bookQuery.getFirstDate())
                    .set("lastDate", bookQuery.getLastDate())
                    .set("status", bookQuery.getStatus())
                    .set("currTime", bookQuery.getCurrTime())
                    .set("bookDate", bookQuery.getBookDate());
            SqlPara sqlPara = Book.dao.getSqlPara(Book.book_pageModel, set);
            sqlPara.setSql(sqlPara.getSql().replaceFirst(" AND ", " WHERE "));
            retVal = Book.dao.find(sqlPara);
            CacheKit.put(Book.book_modelList, String.valueOf(bookQuery), retVal);
        }
        return retVal;
    }

    public List<Book> findRecordByMe(BookQuery bookQuery) {
        List<Book> retVal = null;
        retVal = CacheKit.get(Book.book_findRecordByMe, String.valueOf(bookQuery));
        if (retVal == null) {
            Kv set = Kv.by("userId", bookQuery.getParams());
            SqlPara sqlPara = Book.dao.getSqlPara(Book.book_findRecordByMe, set);
            sqlPara.setSql(sqlPara.getSql().replaceFirst(" AND ", " WHERE "));
            retVal = Book.dao.find(sqlPara);
            CacheKit.put(Book.book_findRecordByMe, String.valueOf(bookQuery), retVal);
        }
        return retVal;
    }

    public void approveService(ApproveForm approveForm) {
        if (approveForm == null || approveForm.getId() == null || approveForm.getStatus() == null)
            throw new HandlerException(ResultEnum.DATA_ERROR, "提交的表单不合法");

        //审批通过时验证预定时间段和不合法
        if (approveForm.getStatus() == 1) {
            Book thisBook = Book.dao.findById(approveForm.getId());
            Long bookDate = thisBook.getBookDate();
            SqlPara sql = Book.dao.getSqlPara(Book.book_isApprove, Kv.by("bookDate", bookDate));
            List<Book> books = Book.dao.find(sql);
            books.forEach(book -> {
                Long thisStartTime = thisBook.getStartTime().getTime();
                Long thisEndTime = thisBook.getEndTime().getTime();
                Long startTime = book.getStartTime().getTime();
                Long endTime = book.getEndTime().getTime();
                if ((book.getRoom() == thisBook.getRoom()) && ((thisStartTime >= startTime && thisStartTime < endTime) || (thisStartTime < startTime && thisEndTime > startTime)))
                    throw new HandlerException(ResultEnum.DATA_ERROR,
                            DateUtil.format(thisBook.getStartTime(), "yyyy-MM-dd HH:mm:ss") + "至" + DateUtil.format(thisBook.getEndTime(), "yyyy-MM-dd HH:mm:ss") + "已被预订！");
            });
        }

        Book book = getModel(approveForm.getId())
                .setStatus(approveForm.getStatus())
                .setBookApprover(approveForm.getApprover())
                .setRefuse(approveForm.getRefuse());
        book.update();
        remove();
        // 发送一个完成审批事件
        EventKit.post(new ApproveEvent(book, "预订结果"));
    }

    public void bookMeeting(BookForm bookForm) {
        //验证预定时间段合法性
        SqlPara sql = Book.dao.getSqlPara(Book.book_isBook, Kv.by("bookDate", DateUtil.parse(bookForm.getDate()).getTime()));
        List<Book> books = Book.dao.find(sql);
        books.forEach(book -> {
            String[] time = bookForm.getTime().split("-");
            String date = bookForm.getDate();
            String startTimeStr = date + " " + time[0];
            String endTimeStr = date + " " + time[1];
            Long thisStartTime = DateUtil.parse(startTimeStr).getTime();
            Long thisEndTime = DateUtil.parse(endTimeStr).getTime();
            Long startTime = book.getStartTime().getTime();
            Long endTime = book.getEndTime().getTime();
            if ((bookForm.getRoomId() == book.getRoom()) && ((thisStartTime >= startTime && thisStartTime < endTime) || (thisStartTime < startTime && thisEndTime > startTime)))
                throw new HandlerException(ResultEnum.DATA_ERROR,
                        startTimeStr + "至" + endTimeStr + "已被预订！");
        });

        Book book = new Book();
        String timeSlot = bookForm.getTime();
        if (StrKit.isBlank(timeSlot))
            throw new HandlerException(ResultEnum.DATA_ERROR, "请输入预定时间段");
        String[] timeSlots = timeSlot.split("-");
        if (timeSlots.length != 2)
            throw new HandlerException(ResultEnum.DATA_ERROR, "时间段不合法");

        String dateStr = bookForm.getDate();
        if (StrKit.isBlank(dateStr))
            throw new HandlerException(ResultEnum.DATA_ERROR, "请输入预定日期");

        //预定时间小于当前时间
        String bookTimeStr = dateStr + " " + timeSlots[0];
        Long dateTime = null;
        try {
            dateTime = DateUtil.parse(bookTimeStr, "yyyy-MM-dd HH:mm").getTime();
        } catch (Exception e) {
            throw new HandlerException(ResultEnum.DATA_ERROR, "时间段不合法");
        }
        if (dateTime < System.currentTimeMillis())
            throw new HandlerException(ResultEnum.DATA_ERROR, "无法预定当前时间之前的时间段");

        book.setBookDate(DateUtil.parse(bookForm.getDate()).getTime())
                .setReason(bookForm.getBookReason())
                .setBookUser(bookForm.getUserId())
                .setStartTime(DateUtil.parse(bookForm.getDate() + " " + timeSlots[0], "yyyy-MM-dd HH:mm"))
                .setEndTime(DateUtil.parse(bookForm.getDate() + " " + timeSlots[1], "yyyy-MM-dd HH:mm"))
                .setStatus(0)
                .setRoom(bookForm.getRoomId());
        boolean isSave = book.save();
        if (!isSave)
            throw new HandlerException(ResultEnum.DATA_ERROR, "预定失败");
        remove();
        // 发送一个完成预定事件
        EventKit.post(new BookMeetEvent(book, "审批预订"));
    }

    public void cancel(Long id) {
        this.deleteById(id);
    }


    public void remove() {
        CacheKit.removeAll(Book.book_recordList);
        CacheKit.removeAll(Book.book_getModel);
        CacheKit.removeAll(Book.book_pageModel);
        CacheKit.removeAll(Book.book_pageRecord);
        CacheKit.removeAll(Book.book_getRecord);
        CacheKit.removeAll(Book.book_modelList);
        CacheKit.removeAll(Book.book_findRecordByMe);
    }
}
